package kyuu.acshmily.video
{
	import flash.events.Event;
	import flash.events.NetStatusEvent;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
	import flash.media.SoundTransform;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.utils.Timer;
	
	import kyuu.acshmily.events.VideoEvent;
	import kyuu.acshmily.utils.CommonUtils;
	
	import mx.core.UIComponent;
	import mx.events.ResizeEvent;

	// 标识本组件调度的事件
	[Event(name="progress", type="flash.events.ProgressEvent")]
	[Event(name="complete", type="flash.events.Event")]
	[Event(name="ready", type="kyuu.acshmily.events.VideoEvent")]
	[Event(name="stopped", type="kyuu.acshmily.events.VideoEvent")]
	[Event(name="playheadUpdate", type="kyuu.acshmily.events.VideoEvent")]
	[Event(name="sought", type="kyuu.acshmily.events.VideoEvent")]
	[Event(name="partComplete", type="kyuu.acshmily.events.VideoEvent")]
	[Event(name="partPlaying", type="kyuu.acshmily.events.VideoEvent")]

	/**
	 * 播放视频组件
	 */
	public class VideoComponent extends UIComponent
	{
		// 内部组件
		private var _video:Video = null;
		private var _timer:Timer = null;

		// 内部变量
		private var _netConn:NetConnection;
		private var _netStreams:Array;
		private var _videoInfos:Array;

		// 状态变量
		private var _isReady:Boolean = false;	// 是否可以开始播放，该状态只通知一次
		private var _isBufferComplete:Boolean = false;	//是否缓冲完成
		private var _isPlaying:Boolean = false;	// 是否正在播放
		private var _bufferIndex:int = -1;	// 缓冲索引
		private var _playIndex:int = -1;	// 播放索引
		private var _metaArrive:Array = null;	// 元数据是否到达

		// 控制变量
		private var _isSmooth:Boolean = true;
		private var _isRepeat:Boolean = false;	// 是否循环播放
		private var _keepAspectRatio:Boolean = true;	// 是否保持横总比
		private var _volumn:Number = CommonUtils.DEFAULT_VOLUMN;	// 播放音量

		// 对外变量
		private var _videoLength:Number = 0;

		public function VideoComponent(){
			super();

			// 初始化计时器
			_timer = new Timer(100);
			_timer.addEventListener(TimerEvent.TIMER, timerHandler);
		}

		override protected function createChildren() : void{
			super.createChildren();

			// 添加Video组件
			_video = new Video();
			_video.smoothing = _isSmooth;
			addChild(_video);
			_video.x = 0;
			_video.y = 0;
			// 监听改变大小的事件
			addEventListener(ResizeEvent.RESIZE, resizeHandler);
		}
		
		/************************ 内部事件响应函数 ************************/
		/**
		 * 组件大小被改变时的事件响应
		 */
		private function resizeHandler(e:ResizeEvent):void{
			adjustVideoSize();
		}

		/**
		 * 网络连接事件响应
		 */
		private function netConnectionHandler(e:NetStatusEvent):void{
			if(e.info.code == "NetConnection.Connect.Success"){
				// 缓冲第一段视频
				_bufferIndex = 0;
				bufferVideo();

				// 启动计时器
				_timer.start();
			}
			else{
				trace("netConnectionHandler: " + e.info.code);
			}
		}

		/**
		 * 网络流事件响应
		 */
		private function netStreamHandler(e:NetStatusEvent):void{
			if(e.info.code == "NetStream.Play.StreamNotFound"){
				// 找不到视频流，使用缺省视频流
				var vi:VideoInfo = _videoInfos[_bufferIndex] as VideoInfo;
				vi.videoUrl = CommonUtils.NULL_FLV_URL;
				vi.videoLength = CommonUtils.NULL_FLV_LENGTH;
				// 重新计算视频时间
				updateVideoLength();
				// 缓冲缺省的视频
				bufferVideo();
			}
			else if(e.info.code == "NetStream.Play.Start"){
				var ns:NetStream = e.target as NetStream;
				ns.pause();
				ns.seek(0);
			}
			else if(e.info.code == "NetStream.Play.Stop"){
				// 当前分段播放完成
				_playIndex++;
				if(_playIndex == _videoInfos.length) _playIndex = 0;
				// 跳到下一段
				jump(_playIndex);
				// 如果全部播放完成，则暂停
				if(_playIndex == 0){
					// 调度视频停止事件
					var ve:VideoEvent = new VideoEvent(VideoEvent.STOPPED);
					dispatchEvent(ve);
					// 判断是否循环播放
					if(!_isRepeat) pause();
				}
			}
			else{
				trace("netStreamHandler: " + e.info.code);
			}
		}

		/**
		 * 计时器事件响应函数
		 */
		private function timerHandler(e:TimerEvent):void{
			var i:int = 0;
			var vi:VideoInfo;
			var ns:NetStream;

			var ve:VideoEvent;
			
			// 调度缓冲事件
			if(!_isBufferComplete){
				// 计算已经缓冲的时间
				var bufferedTime:Number = 0;
				for(i=0; i<_bufferIndex; i++){
					vi = _videoInfos[i] as VideoInfo;
					bufferedTime += vi.videoLength;
				}
				ns = _netStreams[_bufferIndex] as NetStream;
				bufferedTime += VideoInfo(_videoInfos[_bufferIndex]).videoLength * ns.bytesLoaded / ns.bytesTotal;
				// 调度缓冲进度事件
				var pe:ProgressEvent = new ProgressEvent(ProgressEvent.PROGRESS, false, false, bufferedTime, _videoLength);
				dispatchEvent(pe);

				// 判断是否缓冲完成并获取到元数据
				if(ns.bytesLoaded>=ns.bytesTotal && _metaArrive[_bufferIndex]){
					// 调度分段缓冲完成事件
					ve = new VideoEvent(VideoEvent.PART_COMPLETE, false, false, _bufferIndex, 0);
					dispatchEvent(ve);

					// 开始缓冲下一个分段
					_bufferIndex++;
					if(_bufferIndex >= _videoInfos.length){
						// 全部视频分段缓冲完成
						_isBufferComplete = true;
						// 调度缓冲完成事件
						var ce:Event = new Event(Event.COMPLETE);
						dispatchEvent(ce);
					}
					else{
						// 缓冲下一个视频分段
						bufferVideo();
					}
				}
			}

			// 调度播放头更新事件
			var playedTime:Number = 0;
			for(i=0; i<_playIndex; i++){
				vi = _videoInfos[i] as VideoInfo;
				playedTime += vi.videoLength;
			}
			ns = _netStreams[i] as NetStream;
			playedTime += ns.time * 1000;
			ve = new VideoEvent(VideoEvent.PLAYHEAD_UPDATE, false, false, _playIndex, playedTime);
			dispatchEvent(ve);
		}

		/**
		 * 媒体信息到达时的响应函数
		 */
		public function onMetaData(info:Object):void{
			if(_bufferIndex >= _videoInfos.length) return;

			// 获取当前正在缓冲的视频信息
			var vi:VideoInfo = _videoInfos[_bufferIndex] as VideoInfo;

			// 将视频的信息更新到视频组件类中
			vi.videoWidth = info.width;
			vi.videoHeight = info.height;
			// 更新flv的播放时间（暂不使用）
			//vi.videoLength = info.duration;

			// 重设视频信息数组
			_videoInfos[_bufferIndex] = vi;

			// 元信息标识
			_metaArrive[_bufferIndex] = true;

			if(!_isReady){
				_isReady = true;
				jump(0);
				
				// 调度准备就绪的事件
				var ve:VideoEvent = new VideoEvent(VideoEvent.READY);
				dispatchEvent(ve);
			}
		}

		public function onCuePoint(info:Object):void{}
		
		public function onLastSecond(info:Object):void{}

		/************************ 内部调用函数 ************************/
		/**
		 * 缓冲当前视频
		 */
		private function bufferVideo():void{
			// 获取要加载的视频信息
			var vi:VideoInfo = _videoInfos[_bufferIndex] as VideoInfo;

			// 缓冲该视频
			var ns:NetStream = new NetStream(_netConn);
			ns.client = this;
			ns.bufferTime = CommonUtils.BUFFER_TIME;
			ns.addEventListener(NetStatusEvent.NET_STATUS, netStreamHandler);
			_netStreams[_bufferIndex] = ns;
			ns.play(vi.videoUrl);
		}

		/**
		 * 调整视频组件的大小
		 */
		private function adjustVideoSize():void{
			if(_playIndex>=0 && _keepAspectRatio){
				// 获取正在播放的视频信息
				var vi:VideoInfo = _videoInfos[_playIndex] as VideoInfo;
				// 计算视频的横纵比
				var videoAR:Number = vi.videoWidth / vi.videoHeight;
				// 计算组件的横纵比
				var compAR:Number = width / height;

				// 在保持横纵比的基础上，计算视频组件大小
				var newWidth:Number = width;
				var newHeight:Number = height;
				if(compAR >= videoAR)
					newWidth = newHeight * videoAR;
				else
					newHeight = newWidth / videoAR;

				// 重设视频组件的大小 
				_video.width = newWidth;
				_video.height = newHeight;
				// 重设视频组件的坐标，使其居中
				_video.x = (width - newWidth) / 2;
				_video.y = (height - newHeight) / 2;
			}
			else{
				_video.width = width;
				_video.height = height;
			}
		}

		/**
		 * 更新视频的时间长度
		 */
		private function updateVideoLength():void{
			for(var i:int=0; i<_videoInfos.length; i++){
				var vi:VideoInfo = _videoInfos[i] as VideoInfo;
				_videoLength += vi.videoLength;
			}
		}

		/************************ getter & setter ************************/
		public function get totalTime():Number{
			return _videoLength;
		}

		public function get playHead():Number{
			var _playHead:Number = 0;
			for(var i:int=0; i<_playIndex; i++){
				var vi:VideoInfo = _videoInfos[i] as VideoInfo;
				_playHead += vi.videoLength;
			}
			var ns:NetStream = _netStreams[i] as NetStream;
			_playHead += ns.time * 1000;

			return _playHead;
		}

		public function get playing():Boolean{
			return _isPlaying;
		}

		public function set repeat(value:Boolean):void{
			_isRepeat = value;
		}
		/************************ 对外API接口 ************************/
		/**
		 * 加载视频
		 * @param videoInfos - 视频信息数组
		 */
		public function load(videoInfos:Array):void{
			_videoInfos = CommonUtils.copyVideoInfos(videoInfos);
			if(_videoInfos == null) return;
			_netStreams = new Array(_videoInfos.length);
			// 初始化标志位
			_metaArrive = new Array(_videoInfos.length);
			for(var i:int=0; i<_metaArrive.length; i++) _metaArrive[i] = false;

			_bufferIndex = 0;
			_isBufferComplete = false;
			updateVideoLength();

			// 创建网络连接
			_netConn = new NetConnection();
			_netConn.addEventListener(NetStatusEvent.NET_STATUS, netConnectionHandler);
			_netConn.connect(null);
		}

		/**
		 * 关闭视频
		 * 用于释放资源，一般不调用
		 */
		public function close():void{
			if(_netConn == null) return;
			_netConn.removeEventListener(NetStatusEvent.NET_STATUS, netConnectionHandler);
			_netConn.close();
			_netConn = null;
		}

		/**
		 * 播放
		 */
		public function play():void{
			var ns:NetStream = _netStreams[_playIndex] as NetStream;
			if(ns == null) return;

			ns.resume();
			if(!_timer.running) _timer.start();
			
			_isPlaying = true;
		}

		/**
		 * 暂停
		 */
		public function pause():void{
			var ns:NetStream = _netStreams[_playIndex] as NetStream;
			if(ns == null) return;

			ns.pause();
			if(_isBufferComplete) _timer.stop();

			_isPlaying = false;
		}

		/**
		 * 停止
		 */
		public function stop():void{
			_playIndex = 0;
			var ns:NetStream = _netStreams[_playIndex] as NetStream;
			if(ns == null) return;

			_video.clear();
			_video.attachNetStream(ns);
			ns.soundTransform = new SoundTransform(_volumn);
			ns.pause();
			ns.seek(0);
		}

		/**
		 * 跳转到指定时间
		 * @param seekTime - 目标时间
		 */
		public function seek(seekTime:Number):void{
			var destIndex:int = -1;
			var destTime:Number = seekTime;

			for(var i:int=0; i<_videoInfos.length; i++){
				var vi:VideoInfo = _videoInfos[i] as VideoInfo;
				if(destTime >= vi.videoLength)
					destTime -= vi.videoLength;
				else{
					destIndex = i;
					break;
				}
			}
			jump(destIndex, destTime);
		}

		/**
		 * 调整音量
		 * @param volumn - 音量大小(0.0~1.0)
		 */
		public function setVolumn(volumn:Number):void{
			_volumn = volumn;

			var ns:NetStream = _netStreams[_playIndex] as NetStream;
			ns.soundTransform = new SoundTransform(_volumn);
		}

		/**
		 * 播放指定的分段
		 * @param playIndex - 要播放的分段的索引
		 * @param seekTime - 分段的指定位置
		 */
		public function jump(playIndex:int, seekTime:Number=0):void{
			// 暂停当前的分段
			var ns:NetStream = _netStreams[_playIndex] as NetStream;
			if(ns != null) ns.pause();

			// 判断是否跳转了分段
			var partChanged:Boolean = (playIndex!=_playIndex);

			// 获取新的分段
			_playIndex = playIndex;
			ns = _netStreams[_playIndex] as NetStream;
			if(ns == null) return;

			// 将新的分段视频流附件到Video
			_video.clear();
			_video.attachNetStream(ns);
			// 调整大小、音量和时间
			adjustVideoSize();
			ns.soundTransform = new SoundTransform(_volumn);
			ns.seek(seekTime / 1000);
			// 播放或暂停
			if(_isPlaying) play();
			else pause();

			// 计算跳转到的时间
			var newTime:Number = 0;
			for(var i:int=0; i<_playIndex; i++){
				var vi:VideoInfo = _videoInfos[i] as VideoInfo;
				newTime += vi.videoLength;
			}
			newTime += seekTime;
			// 调度跳转事件
			var ve:VideoEvent = new VideoEvent(VideoEvent.SOUGHT, false, false, _playIndex, newTime);
			dispatchEvent(ve);

			// 判断是否跨段落
			if(partChanged){
				// 调度分段播放事件 
				ve = new VideoEvent(VideoEvent.PART_PLAYING, false, false, _playIndex, 0);
				dispatchEvent(ve);
			}
		}
	}
}